import requests
from bs4 import BeautifulSoup
import pandas as pd
import os
import re
import tkinter as tk
from tkinter import messagebox, scrolledtext
from datetime import datetime


class LotteryCrawler:
    def __init__(self):
        self.data_file = "dlt_history.csv"
        self.columns = ["期号", "开奖日期", "前区号码", "后区号码"]

    def get_latest_period(self):
        """获取本地数据中最新的期号"""
        if os.path.exists(self.data_file):
            try:
                df = pd.read_csv(self.data_file)
                if len(df) > 0:
                    # 按期号排序，获取最新期号
                    df_sorted = df.sort_values('期号', ascending=False)
                    return df_sorted.iloc[0]['期号']
            except:
                pass
        return None

    def crawl_history_data(self):
        """从指定网页爬取历史数据，只获取新数据"""
        all_data = []

        # 目标网页URL
        url = "https://datachart.500.com/dlt/history/newinc/history.php?start=001&end=99999"

        try:
            headers = {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
                "Referer": "https://datachart.500.com/dlt/",
            }

            print("正在访问网页...")
            response = requests.get(url, headers=headers, timeout=15)
            response.encoding = 'gb2312'  # 这个网站使用gb2312编码

            # 获取本地最新期号
            latest_local_period = self.get_latest_period()
            print(f"本地最新期号: {latest_local_period}")

            # 解析HTML
            soup = BeautifulSoup(response.text, 'html.parser')

            # 查找数据表格
            table = soup.find('table', {'id': 'tdata'})
            if not table:
                table = soup.find('table', {'class': 'tchart'})

            if table:
                print("找到数据表格")
                rows = table.find_all('tr')
                new_data_count = 0
                found_latest = False

                # 从最后一行开始向前遍历（因为网页数据是从旧到新排列的）
                for row in reversed(rows):
                    # 跳过表头行
                    if row.find('th'):
                        continue

                    cols = row.find_all('td')
                    if len(cols) >= 15:
                        # 期号 - 第1列
                        period = cols[0].text.strip()

                        # 如果已经有本地数据，且遇到已存在的期号，跳过
                        if latest_local_period and period == latest_local_period:
                            found_latest = True
                            continue

                        # 如果已经找到最新期号，但后面又遇到更早的期号，跳过（确保只获取新数据）
                        if found_latest and latest_local_period and int(period) < int(latest_local_period):
                            continue

                        # 前区号码 - 第2-6列
                        front_nums = []
                        for i in range(1, 6):
                            num = cols[i].text.strip().zfill(2)
                            front_nums.append(num)

                        # 后区号码 - 第7-8列
                        back_nums = []
                        for i in range(6, 8):
                            num = cols[i].text.strip().zfill(2)
                            back_nums.append(num)

                        # 开奖日期 - 最后一列
                        date = cols[-1].text.strip()

                        if len(front_nums) == 5 and len(back_nums) == 2:
                            front_str = " ".join(front_nums)
                            back_str = " ".join(back_nums)
                            all_data.append([period, date, front_str, back_str])
                            new_data_count += 1

                print(f"从页面解析到{new_data_count}期新数据")

            # 如果没有找到新数据，检查是否需要更新
            if not all_data:
                if latest_local_period:
                    return "已是最新数据，无需更新"
                else:
                    # 如果没有本地数据，使用模拟数据
                    return self.use_sample_data()

        except Exception as e:
            print(f"爬取数据时出错: {e}")
            return f"爬取数据时出错: {e}"

        # 保存数据
        if all_data:
            return self.save_data(all_data)
        else:
            return "未获取到新数据"

    def crawl_all_data(self):
        """爬取所有历史数据（用于首次运行）"""
        all_data = []

        # 目标网页URL
        url = "https://datachart.500.com/dlt/history/newinc/history.php?start=001&end=99999"

        try:
            headers = {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
                "Referer": "https://datachart.500.com/dlt/",
            }

            print("正在访问网页获取所有数据...")
            response = requests.get(url, headers=headers, timeout=15)
            response.encoding = 'gb2312'

            # 解析HTML
            soup = BeautifulSoup(response.text, 'html.parser')

            # 查找数据表格
            table = soup.find('table', {'id': 'tdata'})
            if not table:
                table = soup.find('table', {'class': 'tchart'})

            if table:
                print("找到数据表格")
                rows = table.find_all('tr')

                for row in rows:
                    # 跳过表头行
                    if row.find('th'):
                        continue

                    cols = row.find_all('td')
                    if len(cols) >= 15:
                        # 期号 - 第1列
                        period = cols[0].text.strip()

                        # 前区号码 - 第2-6列
                        front_nums = []
                        for i in range(1, 6):
                            num = cols[i].text.strip().zfill(2)
                            front_nums.append(num)

                        # 后区号码 - 第7-8列
                        back_nums = []
                        for i in range(6, 8):
                            num = cols[i].text.strip().zfill(2)
                            back_nums.append(num)

                        # 开奖日期 - 最后一列
                        date = cols[-1].text.strip()

                        if len(front_nums) == 5 and len(back_nums) == 2:
                            front_str = " ".join(front_nums)
                            back_str = " ".join(back_nums)
                            all_data.append([period, date, front_str, back_str])

                print(f"从页面解析到{len(all_data)}期数据")

        except Exception as e:
            print(f"爬取所有数据时出错: {e}")
            return f"爬取所有数据时出错: {e}"

        # 保存数据
        if all_data:
            return self.save_data(all_data)
        else:
            return "未获取到数据"

    def save_data(self, all_data):
        """保存数据到文件"""
        if all_data:
            df = pd.DataFrame(all_data, columns=self.columns)

            if os.path.exists(self.data_file):
                # 读取现有数据
                existing_df = pd.read_csv(self.data_file)
                # 合并数据并去重
                combined_df = pd.concat([df, existing_df], ignore_index=True)
                combined_df.drop_duplicates(subset=["期号"], keep='first', inplace=True)
                combined_df.sort_values(by="期号", ascending=False, inplace=True)
                combined_df.to_csv(self.data_file, index=False)
                added_count = len(combined_df) - len(existing_df)
                result = f"数据已更新，新增{added_count}期，共{len(combined_df)}期"
            else:
                df.sort_values(by="期号", ascending=False, inplace=True)
                df.to_csv(self.data_file, index=False)
                result = f"数据已保存到{self.data_file}，共{len(all_data)}期"

            print(result)
            return result
        else:
            return "未获取到数据"

    def use_sample_data(self):
        """使用模拟数据进行演示"""
        print("使用模拟数据进行演示")
        all_data = [
            ["25104", "2025-09-10", "02 06 09 22 34", "02 08"],
            ["25103", "2025-09-07", "05 12 18 25 31", "03 07"],
            ["25102", "2025-09-03", "08 15 22 29 35", "01 06"],
        ]

        df = pd.DataFrame(all_data, columns=self.columns)
        df.to_csv(self.data_file, index=False)
        return f"使用模拟数据，共{len(all_data)}期"

    def check_numbers(self, numbers):
        """检查号码是否在历史数据中存在"""
        if not os.path.exists(self.data_file):
            return "数据文件不存在，请先获取数据"

        try:
            df = pd.read_csv(self.data_file)
        except:
            return "数据文件读取失败"

        if len(df) == 0:
            return "数据文件为空"

        # 解析用户输入的号码
        try:
            # 支持多种输入格式
            if '|' in numbers:
                front_str, back_str = numbers.split('|')
                front_nums = [x.strip().zfill(2) for x in re.findall(r'\d+', front_str)]
                back_nums = [x.strip().zfill(2) for x in re.findall(r'\d+', back_str)]
            else:
                all_nums = [x.zfill(2) for x in re.findall(r'\d+', numbers)]
                if len(all_nums) != 7:
                    return "请输入7个数字(5个前区+2个后区)"
                front_nums = all_nums[:5]
                back_nums = all_nums[5:]

            # 验证号码范围
            for num in front_nums:
                if int(num) < 1 or int(num) > 35:
                    return f"前区号码{num}超出范围(1-35)"
            for num in back_nums:
                if int(num) < 1 or int(num) > 12:
                    return f"后区号码{num}超出范围(1-12)"

            front_nums.sort()
            back_nums.sort()

            # 转换为字符串格式用于比较
            user_front_str = " ".join(front_nums)
            user_back_str = " ".join(back_nums)

        except Exception as e:
            return f"输入格式错误: {e}"

        # 在历史数据中查找匹配的号码
        results = []
        for _, row in df.iterrows():
            # 检查是否完全匹配
            if user_front_str == row["前区号码"] and user_back_str == row["后区号码"]:
                results.append(f"🎯 完全匹配: 第{row['期号']}期 ({row['开奖日期']})")
                continue

            # 检查匹配情况
            history_front = row["前区号码"].split()
            history_back = row["后区号码"].split()

            front_match = len(set(front_nums) & set(history_front))
            back_match = len(set(back_nums) & set(history_back))

            if front_match >= 2 and back_match >= 1:
                match_level = self.get_match_level(front_match, back_match)
                results.append(
                    f"{match_level} 第{row['期号']}期 ({row['开奖日期']}): 前区{front_match}个, 后区{back_match}个")
            elif front_match >= 1 and back_match >= 2:
                match_level = self.get_match_level(front_match, back_match)
                results.append(
                    f"{match_level} 第{row['期号']}期 ({row['开奖日期']}): 前区{front_match}个, 后区{back_match}个")
            elif back_match >= 2:
                match_level = self.get_match_level(front_match, back_match)
                results.append(
                    f"{match_level} 第{row['期号']}期 ({row['开奖日期']}): 前区{front_match}个, 后区{back_match}个")
            elif front_match >= 3:
                match_level = self.get_match_level(front_match, back_match)
                results.append(
                    f"{match_level} 第{row['期号']}期 ({row['开奖日期']}): 前区{front_match}个, 后区{back_match}个")

        if results:
            return "\n".join(results[:])
        else:
            return "未在历史数据中找到匹配的号码"

    def get_match_level(self, front_match, back_match):
        """根据匹配情况返回中奖等级"""
        if front_match == 5 and back_match == 2:
            return "🔥 一等奖"
        elif front_match == 5 and back_match == 1:
            return "🔥 二等奖"
        elif front_match == 5 and back_match == 0:
            return "🔥 三等奖"
        elif front_match == 4 and back_match == 2:
            return "⭐ 四等奖"
        elif front_match == 4 and back_match == 1:
            return "⭐ 五等奖"
        elif front_match == 3 and back_match == 2:
            return "⭐ 六等奖"
        elif front_match == 4 and back_match == 0:
            return "⭐ 七等奖"
        elif front_match == 3 and back_match == 1:
            return "✅ 八等奖"
        elif front_match == 2 and back_match == 2:
            return "✅ 八等奖"
        elif front_match == 3 and back_match == 0:
            return "✅ 九等奖"
        elif front_match == 1 and back_match == 2:
            return "✅ 九等奖"
        elif front_match == 2 and back_match == 1:
            return "✅ 九等奖"
        elif front_match == 0 and back_match == 2:
            return "✅ 九等奖"
        else:
            return "📊 匹配"

    def get_latest_data(self):
        """获取最新一期开奖数据"""
        if not os.path.exists(self.data_file):
            return "数据文件不存在"

        try:
            df = pd.read_csv(self.data_file)
            if len(df) == 0:
                return "数据文件为空"

            latest = df.iloc[0]  # 第一行是最新的

            result = f"最新一期: 第{latest['期号']}期 ({latest['开奖日期']})\n"
            result += f"前区: {latest['前区号码']}\n"
            result += f"后区: {latest['后区号码']}"

            return result
        except:
            return "数据文件读取失败"


class LotteryGUI:
    def __init__(self):
        self.crawler = LotteryCrawler()
        self.window = tk.Tk()
        self.window.title("体彩大乐透历史数据查询")
        self.window.geometry("800x600")

        self.setup_ui()

        # 程序启动时自动检查更新
        self.auto_update()

    def setup_ui(self):
        # 标题
        title_label = tk.Label(self.window, text="体彩大乐透历史数据查询系统",
                               font=("Arial", 16, "bold"), fg="blue")
        title_label.pack(pady=10)

        # 按钮框架
        button_frame = tk.Frame(self.window)
        button_frame.pack(pady=10)

        # 获取所有数据按钮
        self.crawl_all_button = tk.Button(button_frame, text="获取所有数据",
                                          command=self.crawl_all_data, width=15, bg="lightgreen")
        self.crawl_all_button.pack(side=tk.LEFT, padx=5)

        # 自动更新按钮
        self.update_button = tk.Button(button_frame, text="检查更新",
                                       command=self.auto_update, width=15, bg="lightblue")
        self.update_button.pack(side=tk.LEFT, padx=5)

        # 最新一期按钮
        self.latest_button = tk.Button(button_frame, text="显示最新一期",
                                       command=self.show_latest, width=15, bg="lightyellow")
        self.latest_button.pack(side=tk.LEFT, padx=5)

        # 清空结果按钮
        self.clear_button = tk.Button(button_frame, text="清空结果",
                                      command=self.clear_results, width=15, bg="lightcoral")
        self.clear_button.pack(side=tk.LEFT, padx=5)

        # 输入区域
        input_frame = tk.Frame(self.window)
        input_frame.pack(pady=10, padx=20, fill=tk.X)

        self.input_label = tk.Label(input_frame, text="输入号码:", font=("Arial", 12))
        self.input_label.pack(anchor=tk.W)

        # 号码输入框
        self.input_entry = tk.Entry(input_frame, width=60, font=("Arial", 11))
        self.input_entry.pack(pady=5, fill=tk.X)
        self.input_entry.insert(0, "02 06 09 22 34 02 08")

        # 格式提示
        format_label = tk.Label(input_frame, text="格式: 01 02 03 04 05 06 07 或 01 02 03 04 05 | 06 07",
                                fg="gray", font=("Arial", 9))
        format_label.pack(anchor=tk.W)

        # 查询按钮
        self.check_button = tk.Button(self.window, text="查询号码",
                                      command=self.check_numbers, width=15,
                                      bg="orange", font=("Arial", 12, "bold"))
        self.check_button.pack(pady=10)

        # 结果显示区域
        result_frame = tk.Frame(self.window)
        result_frame.pack(pady=10, padx=20, fill=tk.BOTH, expand=True)

        result_label = tk.Label(result_frame, text="查询结果:", font=("Arial", 12, "bold"))
        result_label.pack(anchor=tk.W)

        self.result_text = scrolledtext.ScrolledText(result_frame, width=90, height=20,
                                                     font=("Consolas", 10))
        self.result_text.pack(fill=tk.BOTH, expand=True)

        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("正在启动...")
        status_bar = tk.Label(self.window, textvariable=self.status_var, bd=1,
                              relief=tk.SUNKEN, anchor=tk.W, font=("Arial", 10))
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)

        # 显示初始提示
        self.result_text.insert(tk.END, "欢迎使用体彩大乐透查询系统！\n")
        self.result_text.insert(tk.END, "1. 点击'获取历史数据'获取开奖记录\n")
        self.result_text.insert(tk.END, "2. 输入号码并点击'查询号码'进行比对\n")
        self.result_text.insert(tk.END, "3. 点击'显示最新一期'查看最新开奖\n\n")
        self.result_text.insert(tk.END, "数据来源: https://datachart.500.com/dlt/\n\n")

    def crawl_all_data(self):
        self.status_var.set("正在获取数据...")
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, "正在从500彩票网获取体彩大乐透历史数据...\n")
        self.window.update()

        result = self.crawler.crawl_all_data()
        self.result_text.insert(tk.END, result + "\n")
        self.status_var.set("数据获取完成")

    def auto_update(self):
        self.status_var.set("更新数据...")
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, "正在从500彩票网获取体彩大乐透历史数据...\n")
        self.window.update()

        result = self.crawler.crawl_history_data()
        self.result_text.insert(tk.END, result + "\n")
        self.status_var.set("数据获取完成")

    def show_latest(self):
        result = self.crawler.get_latest_data()
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, result)
        self.status_var.set("已显示最新一期数据")

    def check_numbers(self):
        numbers = self.input_entry.get()
        if not numbers:
            messagebox.showwarning("警告", "请输入号码")
            return

        self.status_var.set("正在查询号码...")
        self.window.update()

        result = self.crawler.check_numbers(numbers)
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, result)
        self.status_var.set("号码查询完成")

    def clear_results(self):
        self.result_text.delete(1.0, tk.END)
        self.status_var.set("已清空结果")

    def run(self):
        self.window.mainloop()


if __name__ == "__main__":
    # 启动GUI
    app = LotteryGUI()
    app.run()